using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class PaintBoard : MonoBehaviour
{
    public enum ToolsType
    {
        PENCIL,
        FULL,
    }
    struct PixelState
    {
        public PixelState(int x, int y, Color color2)
        {
            position = new Vector2Int(x, y);
            color = color2;
        }
        public Vector2Int position;
        public Color color;
    }

    public Vector2Int imageSize { 
        get { return m_ImageSize; }
        set { m_ImageSize = value; } }

    public ColorChoicer m_ColorChoicer;
    public Camera MainCamera;
    public Image image { get { return m_Image; } }
    public Image m_Image;
    float m_ImageScale = 2;
    Vector2Int m_ImageSize = new Vector2Int(256, 256);
    float m_ImageScaleMax = 64;
    float m_ImageScaleMin = 1f;
    Color m_SlectedColor = Color.red;
    public ToolsType m_ToolType = ToolsType.PENCIL;
    Color [,]m_ImagePixelStates;
    Color m_FullColor;
    Stack<List<PixelState>> m_UndoStack = new Stack<List<PixelState>>();
    Stack<List<PixelState>> m_RedoStack = new Stack<List<PixelState>>();
    List<PixelState> m_OprationPixelList = new List<PixelState>();
    public GameObject m_MaskBoard;
    public GameObject m_MaskBoardButtonBack;
    public GameObject m_Corssing;
    public GameObject m_CorssingButtonBack;

    private void Awake()
    {
        
    }
    void Start() 
    {
    }

    // Update is called once per frame
    void Update()
    {
        m_SlectedColor = m_ColorChoicer.m_Color;
    }
    Vector2 m_PressPosition = new Vector2(0,0);
    Vector2 m_ImageBeforePressPosition = new Vector2(0, 0);
    bool m_IsRightDown = false;
    bool m_IsLeftDown = false;

    public void SetToolType(ToolsType toolType)
    {
        m_ToolType = toolType;

    }
    void Full(Texture2D texture, int x, int y)
    {
        UtilsDraw.FullColor(texture, x, y, m_FullColor, m_SlectedColor);
        //Queue<Vector2Int> fullQueue = new Queue<Vector2Int>();
        //fullQueue.Enqueue(new Vector2Int(x, y));
        //while (fullQueue.Count > 0)
        //{
        //    var tureData = fullQueue.Dequeue();
        //    if (tureData.x > 0 && tureData.y > 0 &&
        //        tureData.x < m_ImageSize.x && tureData.y < m_ImageSize.y &&
        //        IsEqupmentColor(m_ImagePixelStates[tureData.x, tureData.y], m_FullColor))
        //    {
        //        SetPixel(tureData.x, tureData.y, m_SlectedColor);

        //        fullQueue.Enqueue(new Vector2Int(tureData.x+1, tureData.y));
        //        fullQueue.Enqueue(new Vector2Int(tureData.x-1, tureData.y));
        //        fullQueue.Enqueue(new Vector2Int(tureData.x, tureData.y+1));
        //        fullQueue.Enqueue(new Vector2Int(tureData.x, tureData.y-1));
        //    }
        //}
    }

    public void OnPressDown()
    {
        if(m_Image.sprite == null)
        {
            MessageShow.Instance.Messaage("出于奇怪的原因，画板上没有画！");
            return;
        }
        if (Input.GetMouseButtonDown(0))
        {
            m_IsLeftDown = true;
            if(m_ToolType == ToolsType.PENCIL)
            {
                Vector2 vecMouse = GetMousePos();
                var texture = image.sprite.texture;
                vecMouse.x = Mathf.Clamp(vecMouse.x, 0, texture.width);
                vecMouse.y = Mathf.Clamp(vecMouse.y, 0, texture.height);
                m_PreviousDrawPosition = vecMouse;
                SetPixel((int)vecMouse.x, (int)vecMouse.y, m_SlectedColor);
                texture.Apply();
            }
        }
        else
        {
            if (m_IsRightDown == false)
            {
                m_PressPosition = Input.mousePosition;
                m_ImageBeforePressPosition = GetComponent<RectTransform>().position;
            }
            m_IsRightDown = true;
        }
        if (m_ToolType == ToolsType.FULL && m_IsLeftDown)
        {
            var texture = image.sprite.texture;
            Vector2 vecMouse = GetMousePos();
            vecMouse.x = Mathf.Clamp(vecMouse.x, 0, texture.width);
            vecMouse.y = Mathf.Clamp(vecMouse.y, 0, texture.height);

            var selectColor = texture.GetPixel((int)vecMouse.x, (int)vecMouse.y);
            m_FullColor = selectColor;
            if(!UtilsDraw.IsEqupmentColor(m_FullColor, m_SlectedColor))
            {
                Full(texture, (int)vecMouse.x, (int)vecMouse.y);
                NewOption();
            }
            texture.Apply();
        }
    }

    public void OnPressUp()
    {
        if (m_ToolType == ToolsType.PENCIL && m_IsLeftDown)
        {
            NewOption();
        }
        m_PressPosition = new Vector2(0, 0);
        m_PreviousDrawPosition = new Vector2(0, 0);
        m_IsRightDown = false;
        m_IsLeftDown = false;
    }
    Vector2 m_PreviousDrawPosition = new Vector2(0,0);
    public void OnDrag()
    {
        Vector2 pos = GetMousePos();
        Draw(pos);
    }
    public void OnMouseMove()
    {
        //Debug.Log("233");
        //Vector2 pos = GetMousePos();
        //Draw(pos);
    }

    void Draw(Vector2 pos, bool isForce = false)
    {
        if(image.sprite == null ||
            image.sprite.texture == null)
        {
            MessageShow.Instance.Error("because a strange reaeason we can't found pattingboard anymore . please contact developer to slove this problem");
            return;
        }
        var texture = image.sprite.texture;

        if (m_IsRightDown == true)
        {
            Vector2 mousePosition = Input.mousePosition;
            GetComponent<RectTransform>().position = m_ImageBeforePressPosition + (mousePosition - m_PressPosition);
        }
        if (m_IsLeftDown == true && m_ToolType == ToolsType.PENCIL )
        {
            int horizontalLimit = texture.width;
            if (m_MaskBoard.activeSelf)
                horizontalLimit = texture.width / 2 + 1;


            int posX = (int)Mathf.Clamp(pos.x, 0, horizontalLimit);
            int posY = (int)Mathf.Clamp(pos.y, 0, texture.height);
            if ((m_PreviousDrawPosition.x > 0 && m_PreviousDrawPosition.y > 0 ) || isForce) 
            {
                if (!isForce && m_MaskBoard.activeSelf && pos.x > horizontalLimit)
                {
                    m_PreviousDrawPosition = new Vector2(posX, posY);
                    return;
                }
                UtilsDraw.DrawLine(SetPixel, texture, m_PreviousDrawPosition, new Vector2(posX, posY), m_SlectedColor);
                texture.Apply();
            }
            m_PreviousDrawPosition = new Vector2(posX, posY);
        }
    }

    public void OnMouseLeave()
    {
        if (image.sprite == null)
            return;
        var pos = GetMousePos();
        var texture = image.sprite.texture;
        if (m_MaskBoard.activeSelf && (pos.x > texture.width))
            return;
        Draw(GetMousePos(), true);
    }
    public void OnMouseEnter()
    {
        if (image.sprite == null)
            return;
        var pos = GetMousePos();
        var texture = image.sprite.texture;
        if (m_MaskBoard.activeSelf && (pos.x > texture.width))
            return;
        Draw(GetMousePos(), true);
    }

    void SetPixel(int x, int y, Color color)
    { 
        if (x < 0 || x >= m_ImageSize.x || y < 0 || y >= m_ImageSize.y)
            return;
        m_ImagePixelStates[x, y] = color;

        var texture = image.sprite.texture;
        Color oldColor = texture.GetPixel(x, y);
        if(!UtilsDraw.IsEqupmentColor(oldColor, color))
        {
            m_OprationPixelList.Add(new PixelState(x, y, oldColor));
        }
        texture.SetPixel(x, y, color);


        if (m_MaskBoard.activeSelf && x <= texture.width / 2 && x > 0)
        {
            m_ImagePixelStates[texture.width - x, y] = color;
            oldColor = texture.GetPixel(texture.width - x, y);
            if (!UtilsDraw.IsEqupmentColor(oldColor, color))
            {
                m_OprationPixelList.Add(new PixelState(texture.width - x, y, oldColor));
            }
            texture.SetPixel(texture.width - x, y, color);
        }
    }
    public void OnScroll()
    {
        float axis = Input.GetAxis("Mouse ScrollWheel");
        if (m_ImageScale < m_ImageScaleMin && axis < 0 ||
            m_ImageScale > m_ImageScaleMax && axis > 0)
            axis = 0;
        var mousePos = GetMousePos();
        var xScale = mousePos.x / m_ImageSize.x;
        var yScale = mousePos.y / m_ImageSize.y;
        var newImageScale = m_ImageScale + axis * Time.deltaTime * m_ImageSize.y * m_ImageScale;
        newImageScale = Mathf.Clamp(newImageScale, m_ImageScaleMin, m_ImageScaleMax);
        transform.position += (new Vector3(xScale, yScale, 0) * ((m_ImageScale- newImageScale) * m_ImageSize.x));
        m_ImageScale = newImageScale;
        image.GetComponent<RectTransform>().sizeDelta = new Vector2(m_ImageSize.x * m_ImageScale, m_ImageSize.y * m_ImageScale);
    }
    public void ClearUp()
    {
        if (!image.sprite)
            return;

        var texture = image.sprite.texture;
       for(int i=0; i<texture.width; ++i)
        {
            for(int j=0; j<texture.height; ++j)
            {
                SetPixel(i, j, Color.clear);
            }
        }
        NewOption();
        texture.Apply();
    }
    Vector2 GetMousePos()
    {

        Vector2 mousePos = Input.mousePosition;
        Vector2 vecMouse;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(GetComponent<RectTransform>(), Input.mousePosition, null, out vecMouse);

        vecMouse /= m_ImageScale;
        return vecMouse;
    }

    void NewOption()
    {
        m_UndoStack.Push(new List<PixelState>(m_OprationPixelList));
        m_OprationPixelList.Clear();
        m_RedoStack.Clear();
    }
    public void Undo()
    {
        if (m_UndoStack.Count <= 0)
            return;
        var undoList = m_UndoStack.Pop();
        var redoList = new List<PixelState>();
        for (int i=0; i< undoList.Count; ++i)
        {
            Color oldColor = image.sprite.texture.GetPixel(undoList[i].position.x, undoList[i].position.y);
            redoList.Add(new PixelState( undoList[i].position.x, undoList[i].position.y, oldColor));
            image.sprite.texture.SetPixel(undoList[i].position.x, undoList[i].position.y, undoList[i].color);
            m_ImagePixelStates[undoList[i].position.x, undoList[i].position.y] = undoList[i].color;
        }
        m_RedoStack.Push(redoList);
        image.sprite.texture.Apply();
    }
    public void Redo()
    {
        if (m_RedoStack.Count <= 0)
            return;
        var redoList = m_RedoStack.Pop();
        var undoList = new List<PixelState>();
        for (int i = 0; i < redoList.Count; ++i)
        {
            Color oldColor = image.sprite.texture.GetPixel(redoList[i].position.x, redoList[i].position.y);
            undoList.Add(new PixelState(redoList[i].position.x, redoList[i].position.y, oldColor));
            image.sprite.texture.SetPixel(redoList[i].position.x, redoList[i].position.y, redoList[i].color);
            m_ImagePixelStates[redoList[i].position.x, redoList[i].position.y] = redoList[i].color;
        }
        m_UndoStack.Push(undoList);
        image.sprite.texture.Apply();
    }

    public void Reset()
    {
        image.rectTransform.localPosition = new Vector2(-m_ImageSize.x * m_ImageScale / 2, -m_ImageSize.y * m_ImageScale / 2);
    }
    public void SetSprite(Sprite sprite)
    {
        image.GetComponent<RectTransform>().sizeDelta = new Vector2(m_ImageSize.x * m_ImageScale, m_ImageSize.y * m_ImageScale);
        m_ImagePixelStates = new Color[m_ImageSize.x, m_ImageSize.y];

        if (!sprite)
        {
            image.sprite = null;
            return;
        }

        image.sprite = Sprite.Create(new Texture2D(sprite.texture.width, sprite.texture.height), new Rect(0, 0, sprite.texture.width, sprite.texture.height), new Vector2(0.5f, 0.5f));
        image.type = Image.Type.Simple;
        image.sprite.texture.filterMode = FilterMode.Point;

        image.sprite.texture.Reinitialize(sprite.texture.width, sprite.texture.height);
        image.sprite.texture.SetPixels(sprite.texture.GetPixels());
        image.sprite.texture.Apply();
        for(int i=0; i<m_ImageSize.x; ++i)
        {
            for(int j=0; j<m_ImageSize.y; ++j)
            {
                m_ImagePixelStates[i, j] = image.sprite.texture.GetPixel(i, j);
            }
        }

    }

    public void Hide()
    {
        if(gameObject.activeSelf == true)
            gameObject.SetActive(false);
    }
    public void Show()
    {
        if (gameObject.activeSelf == false)
            gameObject.SetActive(true);
    }


    public void OnMaskBoardClicked()
    {
        m_MaskBoard.SetActive(!m_MaskBoard.activeSelf);
        m_MaskBoardButtonBack.SetActive(!m_MaskBoardButtonBack.activeSelf);
    }

    public void OnCrossingClicked()
    {
        m_Corssing.SetActive(!m_Corssing.activeSelf);
        m_CorssingButtonBack.SetActive(!m_CorssingButtonBack.activeSelf);
    }

    public void OnMirrorMaskPressDown(BaseEventData eventdata)
    {

        if (Input.GetMouseButtonDown(0))
        {
            m_IsLeftDown = true;
        }
        else
        {
            if (m_IsRightDown == false)
            {
                m_PressPosition = Input.mousePosition;
                m_ImageBeforePressPosition = GetComponent<RectTransform>().position;
            }
            m_IsRightDown = true;
        }
        m_PreviousDrawPosition = new Vector2(0, 0);

    }
    public void OnMirrorMaskPressUp(BaseEventData eventdata)
    {
        OnPressUp();
        Draw(GetMousePos());
    }
    public void OnMirrorMaskDrag()
    {
        OnDrag();
    }
    public void OnMirrorMaskScroll()
    {
        OnScroll();
    }
    public void OnMirrorMaskEnter()
    {
        //OnMouseLeave();
    }
    public void OnMirrorMaskLeave()
    {
        //OnMouseEnter();
    }
}
